﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Clipping.Infrastructure.Models;
using System.Xml;
using System.IO;

namespace Clipping.Utils
{
    public class ClientInfoProvider
    {

        private static ClientInfoProvider instance = new ClientInfoProvider();

        private string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data", "ClientInfo.xml");

        private bool clientInfoReady = false;
        private DateTime lastModifyTime = default(DateTime);
        private List<ClientInfo> allClientInfos;
        private Dictionary<string, ClassInfo> classInfoDic;
        private Dictionary<string, ClientInfo> clientInfoDic;
        public static ClientInfoProvider GetInstance()
        {
            return instance;
        }
        
        public bool IsClientInfoDownloaded()
        {
            return File.Exists (path);
        }


        public List<ClientInfo> GetAllClientInfos()
        {
            if (!clientInfoReady)
                tryReadClientInfo();
            return this.allClientInfos;
        }

        public Dictionary<string, ClassInfo> GetAllClassInfoDic()
        {
            if (!clientInfoReady)
                tryReadClientInfo();
            return this.classInfoDic;
        }
        public Dictionary<string, ClientInfo> GetAllClientInfoDic()
        {
            if (!clientInfoReady)
                tryReadClientInfo();
            return this.clientInfoDic;
        }
        private void tryReadClientInfo()
        {
            if (System.IO.File.Exists(path))
            {
                this.lastModifyTime = System.IO.File.GetLastWriteTime(path);
                string fileContent = System.IO.File.ReadAllText(path, Encoding.UTF8);
                this.allClientInfos = parse(fileContent);
               
                this.classInfoDic = new Dictionary<string, ClassInfo>();
                if (allClientInfos != null)
                {
                    this.clientInfoDic = this.allClientInfos.ToDictionary(c => c.Id);
                    foreach (var client in allClientInfos)
                    {
                        if (client.Classes != null)
                        {
                            foreach (var c in client.Classes)
                            {
                                addClassInfoToDic(this.classInfoDic, c);
                            }
                        }
                    }
                }
                clientInfoReady = true;
            }
        }

        private void addClassInfoToDic(Dictionary<string, ClassInfo> dic, ClassInfo classInfo)
        {
            dic[classInfo.Id] = classInfo;
            if (classInfo.SubClasses != null)
            {
                foreach (var subClass in classInfo.SubClasses)
                {
                    addClassInfoToDic(dic, subClass);
                }
            }
        }

        private List<ClientInfo> parse(string fileContent)
        {
            List<ClientInfo> clients = new List<ClientInfo>();
            XmlDataDocument xmldoc = new XmlDataDocument();
            xmldoc.LoadXml(fileContent);
            foreach (XmlNode xn in xmldoc.SelectNodes("/ClippingClients/Client"))
            {

                string clientname = xn.Attributes["Name"].Value;
                List<ClassInfo> ci = loadClassInfo(xn);
                List<Field> fields = loadFields(xn);
                List<OptionalField> properties = loadProperties(xn);
                ClientInfo client = new ClientInfo(xn.Attributes["Id"].Value, clientname, ci, fields, properties);
                foreach (var c in ci)
                {
                    c.Client = client;
                }
                clients.Add(client);
            }

            return clients;
        }

        private List<OptionalField> loadProperties(XmlNode xmlnode)
        {
            XmlNode propertyrootnode = xmlnode.SelectSingleNode("Properties");
            List<OptionalField> properties = new List<OptionalField>();
            if (propertyrootnode != null)
            {
                foreach (XmlNode xn in propertyrootnode.SelectNodes("property"))
                {
                    string id = xn.Attributes["Id"].Value;
                    string name = xn.Attributes["Name"].Value;
                    bool multiSelect = false;
                    if (xn.Attributes["MultiSelect"] != null)
                    {
                        string multiSelectStr = xn.Attributes["MultiSelect"].Value;
                        Boolean.TryParse(multiSelectStr, out multiSelect);
                    }
                    OptionalField p = new OptionalField() { Id = id, Name = name, DisplayName = name, MultiSelect = multiSelect, Type = FieldType.Property, Options = loadOptions(xn) };
                    properties.Add(p);
                }
            }
            return properties;
        }

        private List<OptionalField.Option> loadOptions(XmlNode xmlnode)
        {
            Dictionary<string, string> options = new Dictionary<string, string>();
            foreach (XmlNode xn in xmlnode.SelectNodes("option"))
            {
                if (!options.ContainsKey(xn.Attributes["Name"].Value))
                    options.Add(xn.Attributes["Name"].Value, xn.Attributes["Id"].Value);
            }
            List<OptionalField.Option> rtn = new List<OptionalField.Option>();
            foreach (var kv in options)
            {
                OptionalField.Option op = new OptionalField.Option() { Id = kv.Value, Name = kv.Key };
                rtn.Add(op);
            }
            return rtn;
        }

        private List<Field> loadFields(XmlNode xmlnode)
        {
            XmlNode fieldrootnode = xmlnode.SelectSingleNode("Fields");
            List<Field> fields = new List<Field>();
            if (fieldrootnode != null)
            {
                foreach (XmlNode xn in fieldrootnode.SelectNodes("Field"))
                {
                    Field f = new Field() { Id = xn.Attributes["Id"].Value, Name = xn.Attributes["Name"].Value, Type = FieldType.Field, DisplayName = xn.Attributes["Name"].Value };
                    fields.Add(f);
                }
            }
            return fields;
        }

        private List<ClassInfo> loadClassInfo(XmlNode xmlnode)
        {
            XmlNode classrootnode = xmlnode.SelectSingleNode("Classes");
            List<ClassInfo> classes = new List<ClassInfo>();
            if (classrootnode != null)
            {
                foreach (XmlNode xn in classrootnode.ChildNodes)
                {
                    ClassInfo ci = new ClassInfo(xn.Attributes["Id"].Value, xn.Attributes["Name"].Value);
                    loadSubClass(xn, ci);
                    classes.Add(ci);
                }
            }
            return classes;
        }

        private void loadSubClass(XmlNode classnode, ClassInfo classInfo)
        {
            foreach (XmlNode xn in classnode.ChildNodes)
            {
                ClassInfo ci = new ClassInfo(xn.Attributes["Id"].Value, xn.Attributes["Name"].Value);
                classInfo.AddSubClasses(ci);
                loadSubClass(xn, ci);
            }
        }





    }
}
